<template>
    <div class="map--mobile-preview">
        <canvas class="canvas-c" ref="canvasRef" :style="{ pointerEvents: isVR?'none':'auto' }"></canvas>
        <div class="float-el mark-box" ref="markRef">
            <div class="text-item" v-for="item in shapeData" :key="item.id" :id="item.id">{{item.title}}</div>
            <div class="spirit-item" v-for="(item,index) in spiritData" :key="index" :id="'spirit_'+(index+1)">
                <img :src="item.src" alt="">
            </div>
        </div>
        <span class="action-icon" @click.stop="initFrontCamera" :class="{active: isSecondPerspective}">
            <svg-icon name="3d-box" size="30px" />
        </span>
        <span class="action-icon" @click.stop="handleVrClick" :class="{active: isVR}" style="right: 80px;">
            <svg-icon name="vr-video" size="30px" />
        </span>
        <span v-if="targetVisible" class="action-icon" @click.stop="hanleMockMove" style="right: 140px;">
            <svg-icon name="work" color="#e66847" size="30px" />
        </span>
        <div class="north-icon" :style="{transform: `rotate(${northRotate}deg)`}"><svg-icon name="north" size="42px" /></div>
        <div class="target-info" v-if="targetVisible">
            <div style="display: flex; align-items: center;  color: #e66847;"><svg-icon name="target" style="margin-right: 5px;" size="50px" />{{targetName}}</div>
            <div>距离目的地：<span style="font-size: 30px;">{{targetDistance}}</span>米</div>
        </div>
    </div>
</template>
  
<script setup lang="ts">
import { ref, watch, onMounted, onUnmounted, nextTick } from 'vue';
import * as THREE from 'three';
import { OrbitControls } from './OrbitControls.js';
import { CSS2DRenderer,CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js';
import { getBorderPointCollect } from './tools';
import { useEventListener } from '@vueuse/core'
import * as geometric from 'geometric';
import { getMapDetail } from '@/api/map';
import { getFloor,getRobotLocation } from '@/api/robot';
import { useRoute, useRouter } from 'vue-router';
import * as util from  '@/utils';

window.handleShapeActive = handleShapeActive;

const router = useRouter();
const route = useRoute();
const shapeData = ref<Array<any>>([]);
const spiritData = ref<Array<any>>([]);
let navigationData:Array<any> = [];
let aboutGather:Array<any> = [];
let mapWidth = 0;
let mapHeight = 0;
let scene;
let renderer;
let camera;
let css2Renderer;
let controls;
const canvasRef = ref(null);
const markRef = ref(null);
let shapeGroup;
let activeMesh;
let arrowPlane; //定位标识
let pathMesh;
let locationId;
let trackCamera;
let pathPoints;
let floorExtraInfo = {
    floorHeight: 100
};

let isVR = ref(false);
let isSecondPerspective = ref(false);
let clock = new THREE.Clock();
let isMockMove = false;
var delta;
const keyStates = {
    Digit1: false,
    Digit2: false,
    Digit3: false,
    W: false,
    A: false,
    S: false,
    D: false,
};
const placeFloorId = route.params.placeFloorId;
const robotCode = route.params.robotCode;
let proportion = 1;
const northRotate = ref(0);
const robotMapParams = {
    "height": 0,
    "width": 0,
    "x": 0,
    "y": 0
}

const targetDistance = ref(0);
const targetName = ref('');
const targetVisible = ref(false);
let robotMapOffset = [0,0];
let robotMapRotate = 0;
onMounted(async ()=>{
    const floorRes = await getFloor(placeFloorId);
    const floorInfo = floorRes.data;
    const floorExtra = floorInfo.extra?JSON.parse(floorInfo.extra):{};
    robotMapOffset = floorExtra.robotMapOffset?floorExtra.robotMapOffset:[0,0];
    robotMapRotate = floorExtra.robotMapRotate || 0;
    if(floorInfo.activeArea){
        const activeAreaJson = JSON.parse(floorInfo.activeArea);
        for(let key in robotMapParams){
            robotMapParams[key] = parseFloat(activeAreaJson[key]);
        }
    }else{
        alert("机器人slam地图参数获取失败！");
        return 
    }
    const mapId = floorInfo.mapId;
    if(mapId){
        getMapDetail(mapId).then(async res=>{
            console.log(res.data,'0009------------------99')
            document.title = res.data.name;
            const extra = res.data.extra?JSON.parse(res.data.extra):null;
            if(extra){
                floorExtraInfo.floorHeight = parseInt(extra.floorHeight||100)
                proportion = extra.proportion||0;
            }
            analysisSvgMap(res.data.svg);
            await nextTick();
            //建立3d场景
            init3dScene();
            renderShapes();
            renderSpirit();
            //计算路径矩阵
            buildAbutGather();
            //初始化路径
            initRoutePath();
            //更新机器人定位
            updateRobotLocation();
        })
    }
    
})

let tTimer;
let robotSvgLocation;
function updateRobotLocation(){
    getRobotLocation(robotCode).then(res=>{
        const data = res.data;
        const location = formatRobotPointToSvgMap([data.x,data.y]);
        robotSvgLocation = location;
        const sceenLocation = [ location[0] - mapWidth/2, -location[1] + mapHeight/2 ];
        //-mapWidth/2,mapHeight/2
        arrowPlane.position.setX(sceenLocation[0]);
        arrowPlane.position.setY(sceenLocation[1]);
        arrowPlane.rotation.set(0,0,data.yaw - THREE.MathUtils.degToRad(robotMapRotate));
        //更新locationId
        if(!util.isEmpty(navigationData)){
            let distanceArray = navigationData.map(item=>{
               // console.log(item,location)
                return {
                    ...item,
                    distance: geometric.lineLength([item.point,location])
                }
            })
            distanceArray = distanceArray.sort((a,b)=>{
                return a.distance - b.distance;
            })
            locationId = distanceArray[0].id;
        }   
        
        tTimer = setTimeout(() => {
            updateRobotLocation();
        }, 1000);
    })
}

function stopUpdateRobotLocation(){
    clearTimeout(tTimer);
}

function formatRobotPointToSvgMap(p){
    const { x: originX, y: originY, width, height } = robotMapParams;
    const transformOrigin = [width*proportion/2,height*proportion/2];
    //原点在(0,0)的位置
    const position = [ (p[0]-originX)*proportion, (height - ( p[1]-originY))*proportion];
    //偏移
    const [ x, y ] = robotMapOffset;
    //旋转
    const angle = robotMapRotate;
    //旋转结果
    const positionRotateResult = geometric.pointRotate(position,angle,transformOrigin);
    //原始点指的是距离原点的偏移
    return [ positionRotateResult[0] + x, positionRotateResult[1] + y ];
}  

function init3dScene(){
    const size = getViewSize();
    const width = size[0];
    const height =  size[1];
    canvasRef.value.width = width;
    canvasRef.value.height = height;
    scene = new THREE.Scene();
    camera = new THREE.PerspectiveCamera(50,width/height,1,10000);
    camera.position.set(0, 0, 2000); 
    camera.lookAt(0, 0, 0); //坐标原点
    camera.up = new THREE.Vector3(0, 0, 1); //可用于定义鼠标操作旋转轴
    //camera.rotation.z = THREE.MathUtils.degToRad(-180);
    renderer = new THREE.WebGLRenderer(
        {
            canvas: canvasRef.value,
            antialias: true,
            alpha: true
        }
    );
    renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.depthBuffer = false;
    //添加光源
    var light = new THREE.AmbientLight(0xFFFFFF, 1);    
    const light1 = new THREE.DirectionalLight(0xffffff, 0.2); // soft white light
    light1.castShadow = true;
    light1.position.set(200, 0, 1000);
    scene.add(light,light1);

    //创建一个长方体几何对象Geometry
    const geometry = new THREE.BoxGeometry(100, 100, 100); 
    //创建一个材质对象Material
    const material = new THREE.MeshLambertMaterial({
        color: 0xff0000,//0xff0000设置材质颜色为红色
    }); 
    // 两个参数分别为几何体geometry、材质material
    const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
    //设置网格模型在三维空间中的位置坐标，默认是坐标原点
    mesh.position.set(0,10,0);
    //scene.add(mesh); 

    //2D渲染
    css2Renderer = new CSS2DRenderer();
    markRef.value.appendChild(css2Renderer.domElement);
    

    render(); //执行渲染操作
    handleResize();

    //设置相机控件轨道控制器OrbitControls
    controls = new OrbitControls(camera, renderer.domElement);
    // //水平旋转角度
    // controls.minAzimuthAngle = THREE.MathUtils.degToRad(0);
    // controls.maxAzimuthAngle = THREE.MathUtils.degToRad(0);
    // //垂直旋转角
    controls.minPolarAngle = THREE.MathUtils.degToRad(0);
    controls.maxPolarAngle = THREE.MathUtils.degToRad(90);


    controls.mouseButtons = {
        LEFT: THREE.MOUSE.PAN,
        MIDDLE: THREE.MOUSE.DOLLY,
        RIGHT: THREE.MOUSE.ROTATE
    }
    controls.touches = {
        ONE: THREE.TOUCH.ROTATE,
        TWO: THREE.TOUCH.DOLLY_PAN, 
    }
    //controls.enablePan = false;
    //camera.position.set(1000,0,1000);
    //controls.target.set(200,800,0);
    //camera.position.set(200, 200, 1420); 
    controls.update();
    // 如果OrbitControls改变了相机参数，重新调用渲染器渲染三维场景
    controls.addEventListener('change', function () {
        const rotationZ = THREE.MathUtils.radToDeg(camera.rotation.z);
        northRotate.value = rotationZ<0?(360+rotationZ):rotationZ;
        //console.log(THREE.MathUtils.radToDeg(camera.rotation.z),'camera.rotation---camera.rotation---camera.rotation')
    //    console.log(camera.position,'camera.position---camera.position---camera.position')
    //    console.log(controls.target,'controls.target----controls.target----controls.target')

        //render(); //执行渲染操作
    });//监听鼠标、键盘事件

    useEventListener(renderer.domElement,'click',handleShapeClick);

    initTrackCamera();
    
}

function initTrackCamera(){
    const size = getViewSize();
    trackCamera = new THREE.PerspectiveCamera(50,size[0]/size[1],1,3000);
    //trackCamera.up.set(0,0,1);
    trackCamera.position.set(0,0,1000); 
    trackCamera.lookAt(0, 0, 0); //坐标原点
    trackCamera.up = new THREE.Vector3(0, 0, 1);
}

function initFrontCamera(){
    isSecondPerspective.value =! isSecondPerspective.value;
    let position:number[] = []
    if(isSecondPerspective.value){
        position = [0, -1000, 1500]; 
    }else{;
        position = [0,0,1500]
    }
    camera.position.set(...position); 
    controls.target.set(0,0,0);
    //camera.rotation.set(0,0,0)
    camera.lookAt(0, 0, 0); //坐标原点
    controls.update()
}

function setPath(path,pathData){
    for(let d of pathData){
        const d1 = d.slice(1).map(v=>[v[0],-v[1]]);
        if(d[0] == 'M'){
            path.moveTo( ...d1[0] );
        }else if(d[0] == 'L'){
            path.lineTo( ...d1[0] );
        }else if(d[0] == 'C'){
            path.bezierCurveTo( ...d1[0], ...d1[1], ...d1[2] );
        }
    }
    const startPoint = pathData[0][1];
    const endPoint =  pathData[pathData.length-1][1];
    if(endPoint.toString() !=  startPoint.toString()){
        path.lineTo( startPoint[0], -startPoint[1] );
    }
    return path
}

function renderSpirit(){
    const group = new THREE.Group();
    group.name = 'MAP_SPIRIT';
    for (let [index,value] of spiritData.value.entries()) {
        const spirit = new CSS2DObject(markRef.value.querySelector('#spirit_'+(index+1)));
        spirit.position.set(value.x,-value.y,20);
        group.add(spirit);
    }
    group.position.set(-mapWidth/2,mapHeight/2,0);
    scene.add(group);
    //render();
}

function getShapeMaxThickness(){
    return Math.max(...shapeData.value.map(item=>item.thickness));
}

function renderShapes(){
    shapeGroup = new THREE.Group();
    shapeGroup.name = 'MAP_SHAPE';
    shapeData.value.filter(v=>!v.isHole).forEach(item=>{
        //console.log(item.isStair,'900988--')
        if(item.isStair){
            //绘制楼梯
            shapeGroup.add(createStair(item));
        }else{
            const pathData = item.data;
            const shape = new THREE.Shape();
            setPath(shape,pathData);
            if(!util.isEmpty(item.holes)){
                //添加孔洞
                shape.holes = item.holes.map((h=>setPath(new THREE.Path(),h)));
                //以孔洞添加栏杆
                const railings = generateRailing(item.holes,item.color);
                shapeGroup.add(...railings);
            }
            const { color, title, id, thickness, isBottom } = item;
            const extrudeShape = buildExtrudeShape(shape,{
                depth: thickness, 
                bevelEnabled: false, 
                bevelSegments: 1, 
                steps: 1, 
                bevelSize: 1, 
                bevelThickness: 1 
            },
            { color, title, id, isBottom })
            if(isBottom)extrudeShape.position.set(0,0,-thickness)
            if(!isBottom){
                extrudeShape.serviceType = 'shop';

            }
            shapeGroup.add(extrudeShape);

            //名字
            const tag = new CSS2DObject(markRef.value.querySelector('#'+item.id));
            const tagPosition = item.center; 
            //console.log(tagPosition,'tagPosition')
            tag.position.set(tagPosition[0],-tagPosition[1],thickness+1);
            shapeGroup.add(tag);
        }
        
    })
    console.log(mapWidth,mapHeight)
    shapeGroup.position.set(-mapWidth/2,mapHeight/2,0);
    scene.add(shapeGroup);
    ////定位
    initArrowLocation();
    if(!util.isEmpty(navigationData)){
        const location = navigationData.find(item=>item.id==locationId).point
        setLocationArrow(location[0],-location[1]);
    }
    //render(); //执行渲染操作
}

//绘制楼梯
function createStair(shapeData){
    const polygon =  shapeData.data.map(v=>v.slice(1)[0]).map(v=>[v[0],-v[1]]);
    const width = geometric.lineLength([polygon[0],polygon[1]]);
    const height = geometric.lineLength([polygon[1],polygon[2]]);
    const angle = geometric.lineAngle([polygon[0],polygon[1]]);
    
    const stairWidth = 20;
    const stairDepth = 20;
    const steps = Math.ceil( floorExtraInfo.floorHeight / stairDepth); //Math.ceil(width/stairWidth);
    //const stairDepth = Math.ceil( floorExtraInfo.floorHeight / steps);
    const geometry = new THREE.BoxGeometry( stairWidth, height, 20 ); 
    const material = new THREE.MeshBasicMaterial( {...formatRgbaColor(shapeData.color)} ); 
    const cube = new THREE.Mesh( geometry, material ); 
    var lineMtl = new THREE.LineBasicMaterial( { color: 0xffffff, linewidth: 0.5 } )
    let cubeEdges = new THREE.EdgesGeometry(geometry, 1);
    let cubeLine = new THREE.LineSegments(cubeEdges, lineMtl);
    cube.add(cubeLine);

    const stairGroup = new THREE.Group();
    for(let i=0;i<steps;i++){
        const stairItem = cube.clone();
        stairItem.position.set(i*stairWidth,-height/2,-(i+1)*stairDepth);
        stairGroup.add(stairItem);
    }
    stairGroup.position.set(...polygon[0],0);
    stairGroup.rotation.set(0,0,transAngle(angle));
    return stairGroup
}

function generateRailing(paths,color){
    //设置挤压面
    const pts:any = [];
    const deepness = 5; // 厚度
    const height = 20; // 高度
    pts.push(new THREE.Vector2(0, -0.5 * deepness));
    pts.push(new THREE.Vector2(-height, -0.5 * deepness));
    pts.push(new THREE.Vector2(-height, 0.5 * deepness));
    pts.push(new THREE.Vector2(0, 0.5 * deepness));
    const shape = new THREE.Shape(pts);

    return paths.map(item=>{
        const curvePath = new THREE.CurvePath();
        const coords = item.map(v=>{
            return [v[0],...v.slice(1).map(c=>new THREE.Vector3(c[0],-c[1],0))]
        });
        for(let i=0;i<coords.length;i++){
            const d = coords[i];
            const d1 = d.slice(1);
            const index1 = i==0?coords[coords.length-1]:(i-1);
            const index2 = i==coords.length-1?0:(i+1);
            if(d[0] == 'M' || d[0] == 'L'){
                //下一个点是贝塞尔曲线点则不用相连
                if(coords[index2][0] != 'C'){
                    curvePath.add(new THREE.LineCurve3(d1[0],coords[index2][1]));
                }
            }else if(d[0] == 'C'){
                curvePath.add(
                    new THREE.CubicBezierCurve3(
                        coords[index1][coords[index1].length-1],
                        d1[0],d1[1],d1[2]
                    )
                )
            }
        }
        const extrudeSettings = {
            steps: 200,
            bevelEnabled: true,
            bevelThickness: 100,
            extrudePath: curvePath,
        }
        const geometry = new THREE.ExtrudeGeometry(
            shape,
            extrudeSettings
          );
          const material2 = new THREE.MeshBasicMaterial({
            transparent: true,
            wireframe: false,
            ...formatRgbaColor(color)
          });
          const mesh = new THREE.Mesh(geometry, material2);
          mesh.name = 'railing';
          var lineMtl = new THREE.LineBasicMaterial( { color: 0xffffff, linewidth: 0.5 } )
        let cubeEdges = new THREE.EdgesGeometry(geometry, 1);
        let cubeLine = new THREE.LineSegments(cubeEdges, lineMtl);
        mesh.add(cubeLine);
          return mesh
    })
    
}

function getSvgPointMap(data?:any){
    return data.reduce((collect,item)=>{
        return collect.concat(item.slice(1));
    },[])
}

function initArrowLocation(){
    if(!util.isEmpty(navigationData)){
        const location = navigationData.find(item=>item.id==locationId).point
        setLocationArrow(location[0],-location[1]);
    }else{
        setLocationArrow(mapWidth/2,-mapHeight/2);
    }
}

function getShapeOutlineAll(data?:any){
    return data.reduce((collect,item)=>{
        return collect.concat(item.slice(1));
    },[])
}

function formatRgbaColor(color){
    const colors = color.match(/(\d+(\.\d+)?)/g);
    if(!colors){
        return {
            color: 0x000000,
            opacity: 1
        }
    }
    return {
        color: new THREE.Color(`rgb(${colors[0]},${colors[1]},${colors[2]})`),
        opacity: colors[3]
    }
}

function buildExtrudeShape(shape,extrudeSettings,params){
    const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
    const materialConfig = {
        transparent: true,
        emissive: "#000000",
        ...formatRgbaColor(params.color)
    }
    const mesh = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial(materialConfig));
    //mesh.position.set(0, 0, name == "shop"?config.bottomShapDepth:0);
    //mesh.rotation.set(0, 0, 0);
    //mesh.scale.set(1, 1, 1);
    mesh.name = params.title;
    mesh.shapeId = params.id;
    mesh.originColor = materialConfig.color;
    mesh.isBottom = params.isBottom;
    mesh.castShadow = true;//开启投影
    mesh.receiveShadow = true;//接收阴影

    var lineMtl = new THREE.LineBasicMaterial( { color: 0xffffff, linewidth: 0.5 } )
    // var points = new THREE.BufferGeometry().setFromPoints( shape.getPoints());
    // var line = new THREE.Line( points, lineMtl);
    
    //mesh.add(line);
    let cubeEdges = new THREE.EdgesGeometry(geometry, 1);
    let cubeLine = new THREE.LineSegments(cubeEdges, lineMtl);
    mesh.add(cubeLine);

    return mesh
}

function analysisSvgMap(svgString){
    const dom: HTMLDivElement = document.createElement('div');
    dom.innerHTML = svgString;
    const svgDocument:any = dom.querySelector('svg');
    mapWidth = parseFloat(svgDocument?.getAttribute('width')||0);
    mapHeight = parseFloat(svgDocument?.getAttribute('height')||0);
    //解析形状
    const shapeContainer = svgDocument.querySelector('#SHAPE-CONTAINER');
    const childNodes = shapeContainer.childNodes;
    const shapes = Array.from(new Set(childNodes)).filter(item=>{
        const d = item.getAttribute('d');
        return item.nodeName == 'path' && !/(undefined|NaN)/.test(d)
    });
    const shapeObjData = shapes.map((el:any)=>{
        const item = {
            id: el.id,
            title: el.getAttribute('title'),
            color: el.getAttribute('fill'),
            thickness: parseFloat(el.getAttribute('thickness'))||20,
            isHole: el.hasAttribute('is-hole'),//如果为孔洞，则将可能作为另一个形状的洞
            data: getBorderPointCollect(el),
            isBottom: el.hasAttribute('is-bottom'),
            isStair: el.hasAttribute('is-stair'), //是否楼梯，仅矩形区域支持
        }
        item.center = geometric.polygonCentroid(getShapeOutlineAll(item.data));
        const maskId = el.getAttribute('mask-id');
        if(maskId){
            const mask = shapeContainer.querySelector('#'+maskId);
            const holeShapes = Array.from(new Set(mask.querySelectorAll('path')));
            item.holes = holeShapes.map(h=>getBorderPointCollect(h));
        }
        return item
    })
    //console.log(shapeObjData,'shapes')
    shapeData.value = shapeObjData;
    //解析精灵图
    const spiritContainer = svgDocument.querySelector('#SPIRIT-CONTAINER');
    spiritData.value = Array.from(new Set(spiritContainer.childNodes)).map((item:any)=>{
        return {
            x: parseFloat(item.getAttribute('x')||0),
            y: parseFloat(item.getAttribute('y')||0),
            src: item.getAttribute('href')
        }
    });

    //解析路径点navigationData
    const navigationContainer = svgDocument.querySelector('#ROUTE-CONTAINER');
    const navigationPoints =  Array.from(new Set(navigationContainer.querySelectorAll('[c-type=nav-point]')));
    if(!util.isEmpty(navigationPoints)){
        const linkLines = Array.from(new Set(navigationContainer.querySelector('#nav-lines').childNodes));
        navigationData = navigationPoints.map((el:any)=>{
            const point = {
                id: el.id,
                point: [parseFloat(el.getAttribute('cx')||0),parseFloat(el.getAttribute('cy')||0)],
                target: []
            }
            point.target = linkLines.filter(l=>l.getAttribute('start-id')==el.id).map(l=>l.getAttribute('end-id'));
            return point
        })
        locationId = navigationData[0].id;
    }
    
    console.log(navigationData,'navigationDatanavigationDatanavigationDatanavigationData')
    dom.remove();
    
}

useEventListener(window,'resize',handleResize);


function getViewSize(){
    return [ window.innerWidth, window.innerHeight ]
}

function handleResize(){
    const size = getViewSize();
    renderer.setSize(...size);
    css2Renderer.setSize(...size);
    // 全屏情况下：设置观察范围长宽比aspect为窗口宽高比
    camera.aspect = size[0]/ size[1];
    // 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
    // 但是不会每渲染一帧，就通过相机的属性计算投影矩阵(节约计算资源)
    // 如果相机的一些属性发生了变化，需要执行updateProjectionMatrix ()方法更新相机的投影矩阵
    camera.updateProjectionMatrix();
    //render();
}

function setLocationArrow(x,y){
    if(!arrowPlane){
        // var texture = new THREE.TextureLoader().load(new URL(`/src/assets/images/idicator_arrow_new.png`, import.meta.url).href );
        // var geometry = new THREE.PlaneGeometry(80, 80, 1); //new THREE.PlaneGeometry( 10, 30, 1 );
        // var material = new THREE.MeshBasicMaterial({ map: texture, transparent: true, opacity: 1 });
        // material.alphaTest = 0.1;
        // arrowPlane = new THREE.Mesh(geometry, material);
        // scene.add(arrowPlane);

        //绘制3D定位图标
        const shape = new THREE.Shape();
        shape.moveTo( 0, 0 );
        shape.lineTo( -10, 30 );
        shape.lineTo( 70, 0 );
        shape.lineTo( -10, -30 );
        const extrudeSettings = {
            steps: 2,
            depth: 8,
            bevelEnabled: true,
            bevelThickness: 1,
            bevelSize: 1,
            bevelOffset: 0,
            bevelSegments: 1
        };

        const geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings );
        const material = new THREE.MeshLambertMaterial( { 
            color: 0xe6a23c,
            transparent: true,
            opacity: 0.8,
        } );
        arrowPlane = new THREE.Mesh( geometry, material ) ;
        arrowPlane.scale.set(0.8, 0.8, 0.8);
        scene.add(arrowPlane);

    }
    arrowPlane.position.set(x-mapWidth/2, y+mapHeight/2, 5);
    //arrowPlane.rotation.set(0,0,Math.PI/2);
   //arrowPlane.add(trackCamera);
   //trackCamera.up.set(0,0,1);
    //trackCamera.rotation.set(0,Math.PI/2,0);
    // setTimeout(() => {
    //     render();
    // }, 100);
    
}

function initRoutePath(){
    const flowingLineTexture = new THREE.TextureLoader().load( new URL(`/src/assets/images/nav1.png`, import.meta.url).href);
    flowingLineTexture.wrapS = THREE.RepeatWrapping;
    flowingLineTexture.wrapT = THREE.RepeatWrapping;
    flowingLineTexture.repeat.set(20, 1); //水平重复20次
    flowingLineTexture.needsUpdate = true;
    const path = new THREE.CatmullRomCurve3([new THREE.Vector3(0,0,0),new THREE.Vector3(1,1,0)]);

    // path:路径   40：沿着轨迹细分数  2：管道半径   25：管道截面圆细分数
    const geometry1 = new THREE.TubeGeometry(path, 40, 5, 25);
    const material1 = new THREE.MeshLambertMaterial({
        map: flowingLineTexture,
        side: THREE.BackSide,//THREE.BackSide,
        //side:THREE.DoubleSide,//双面显示看到管道内壁,
        //color: 0xff0000
    });
    pathMesh = new THREE.Mesh(geometry1,material1);
    pathMesh.position.set(-mapWidth/2,mapHeight/2,10);
    pathMesh.visible = false;
    scene.add(pathMesh);
}

function getRoutePath(){
    const shapeId = activeMesh?.shapeId;
    const targetShape = shapeData.value.find(item=>item.id == shapeId);
    const lengths = navigationData.map(item=>parseInt(geometric.lineLength([targetShape.center,item.point])));
    const minLength = Math.min(...lengths);
    const targetIndex = lengths.findIndex(num=>num==minLength);
    console.log(minLength,'lengths')
    const startId = locationId;
    const endId = navigationData[targetIndex].id;//'nav_28';
    const resultMap = dijkstra(aboutGather, startId);
    var endIndex = navigationData.findIndex(item=>item.id == endId);

    var result = {};
    result.totalLength = resultMap.LengthArr[endIndex];
    result.data = [];
    resultMap.pathSeq[endIndex].split(',').map(item=>{
        result.data.push(navigationData[item])
    })
    console.log(result,shapeId,'dewafesr-----')

    targetDistance.value = Math.ceil(result.totalLength/proportion)

    const pathItems = result.data.map(item=>new THREE.Vector3(item.point[0], -item.point[1], 0));
    if(robotSvgLocation)pathItems.unshift(new THREE.Vector3(robotSvgLocation[0],-robotSvgLocation[1],0));//robotSvgLocation
    console.log(pathItems,'pathItemspathItemspathItems')
    // 三维样条曲线
    const path = new THREE.CatmullRomCurve3(pathItems);
    //console.log(path.getSpacedPoints(500),'path.getSpacedPoints(500);')
    pathPoints = path.getSpacedPoints(Math.ceil(result.totalLength/5));
    pathMesh.geometry = new THREE.TubeGeometry(path, 40, 5, 25);
    pathMesh.visible = true;
    // // path:路径   40：沿着轨迹细分数  2：管道半径   25：管道截面圆细分数
    // const geometry1 = new THREE.TubeGeometry(path, 40, 5, 25);
    // const material1 = new THREE.MeshLambertMaterial({
    //     map: flowingLineTexture,
    //     side: THREE.BackSide,//THREE.BackSide,
    //     //side:THREE.DoubleSide,//双面显示看到管道内壁,
    //     //color: 0xff0000
    // });
    // const mesh1 = new THREE.Mesh(geometry1,material1);
    // mesh1.position.set(-mapWidth/2,mapHeight/2,10);

    // scene.add(mesh1);
    // setTimeout(()=>{
    //     render();
    // },100)
}

function buildAbutGather(){
    for (var i = 0; i < navigationData.length; i++) {
        aboutGather[i] = [];
        for (var j = 0; j < navigationData.length; j++) {
            var length = Infinity;
            if (i == j) {
                length = 0; //同一个点的矩阵
            } else if ((navigationData[i].target.indexOf(navigationData[j].id) != -1) || (navigationData[j].target.indexOf(navigationData[i].id) != -1)) {
                length =  geometric.lineLength([navigationData[i].point,navigationData[j].point])//getLengthFromTwoPoint(navigationData[i], navigationData[j]);
            }
            aboutGather[i][j] = length;
        }
    }
    //console.log(aboutGather,'aboutGather---')
    //console.log(dijkstra(aboutGather, 'nav_2'),'result----result-------result-----result')
    //getRoutePath();
}

function dijkstra(path:any[], startId) {
    let recordPath: any = [];
    var m = path && path.length;
    var n = m && path[0].length;
    var index = navigationData.findIndex(item=>item.id == startId);

    if (m && n && m === n && index < n) {
        //初始化distance
        var dis:any = [];
        var i;
        for (i = 0; i < n; i++) {
            dis.push(path[index][i]);
        }
        var flag: any = []; //用于标识index号至其他顶点的距离是否确定
        for (i = 0; i < n; i++) {
            flag.push(false)
            recordPath[i] = '' + index + ',' + i; //[index,i];//
        }
        flag[index] = true;

        var min, minIndex;
        for (i = 0; i < n; i++) {
            min = Infinity;
            //找出剩余的不确定的点到index最短的距离对应的索引
            for (var j = 0; j < n; j++) {
                if (!flag[j] && dis[j] < min) {
                    min = dis[j];
                    minIndex = j;
                    if (j == 6) {
                        console.log(dis[j], '1')
                    }
                }
            }
            //console.log(i+' first time->',dis,'change');
            flag[minIndex] = true; //标识index到此顶点的距离已经确认
            for (var k = 0; k < n; k++) {
                //判断minIndex到k之间有无道路
                if (path[minIndex][k] < Infinity) {
                    //更新distance
                    if (dis[k] > dis[minIndex] + path[minIndex][k]) {
                        dis[k] = dis[minIndex] + path[minIndex][k];
                        /*recordPath[minIndex].push(k);
                        recordPath[k] = recordPath[minIndex];*/
                        recordPath[k] = recordPath[minIndex] + "," + k;

                    }
                } else {

                }
            }

        }
        //console.log(recordPath);
        return {
            LengthArr: dis,
            pathSeq: recordPath
        }
    } else {
        throw new Error("数据有误")
    }
}

function handleShapeClick(event){
    const px = event.offsetX;
    const py = event.offsetY;
    const size = getViewSize();
    //屏幕坐标px、py转WebGL标准设备坐标x、y
    //width、height表示canvas画布宽高度
    const x = (px / size[0]) * 2 - 1;
    const y = -(py / size[1]) * 2 + 1;
    //创建一个射线投射器`Raycaster`
    const raycaster = new THREE.Raycaster();
    //.setFromCamera()计算射线投射器`Raycaster`的射线属性.ray
    // 形象点说就是在点击位置创建一条射线，射线穿过的模型代表选中
    raycaster.setFromCamera(new THREE.Vector2(x, y), camera);
    //.intersectObjects([mesh1, mesh2, mesh3])对参数中的网格模型对象进行射线交叉计算
    // 未选中对象返回空数组[],选中一个对象，数组1个元素，选中两个对象，数组两个元素
    const intersects = raycaster.intersectObjects([shapeGroup]);
    //console.log("射线器返回的对象", shapeGroup, intersects);
    // intersects.length大于0说明，说明选中了模型
    pathMesh.visible = false;
    targetVisible.value = false;
    if(activeMesh)activeMesh.material.color.set(activeMesh.originColor);
    if (intersects.length > 0) {
        // 选中模型的第一个模型，设置为红色
        // console.log(intersects[0].object,'intersects[0].object')
        // if(intersects[0].object.name == 'railing'){
        //     return
        // }
        // if(!intersects[0].object.isBottom){
        //     if(activeMesh)activeMesh.material.color.set(activeMesh.originColor);
        //     activeMesh = intersects[0].object;
        //     activeMesh.material.color.set(0xE6A23C);
            //绘制路线
            // if(!util.isEmpty(navigationData))getRoutePath();
        //}
        if(intersects[0].object.serviceType == 'shop'){
            if(activeMesh)activeMesh.material.color.set(activeMesh.originColor);
            handleActiveMesh(intersects[0].object);
            // activeMesh = intersects[0].object;
            // activeMesh.material.color.set(0xE6A23C);
            // //绘制路线
            // if(!util.isEmpty(navigationData)){
            //     targetName.value = activeMesh.name;
            //     targetVisible.value = true;
            //     getRoutePath();
            // }
        }
        //handleShapeActive();
    }else{
        
        

    }
    //render();
}

function handleActiveMesh(object){
    activeMesh = object;
    activeMesh.material.color.set(0xE6A23C);
    //绘制路线
    if(!util.isEmpty(navigationData)){
        targetName.value = activeMesh.name;
        targetVisible.value = true;
        getRoutePath();
    }
}

function handleShapeActive(name){
    for(let i=0;i<shapeGroup.children.length;i++){
        const item = shapeGroup.children[i];
        const word = name.trim().toLowerCase();
        if(item.name.toLowerCase().indexOf(word)>-1){
            handleActiveMesh(item);
            break;
        }
    }
}

useEventListener(document,'keydown',handlekeydown);
useEventListener(document,'keyup',handlekeyup);

function handlekeydown(e){
    const code = e.code;
    if (code === 'Digit1') keyStates.Digit1 = true;
    if (code === 'Digit2') keyStates.Digit2 = true;
    if (code === 'Digit3') keyStates.Digit3 = true;
    if (code === 'KeyW') keyStates.W = true;
    if (code === 'KeyA') keyStates.A = true;
    if (code === 'KeyS') keyStates.S = true;
    if (code === 'KeyD') keyStates.D = true;





    //console.log(e.keyCode,e,'uiuiu')

   // var delta = clock.getDelta(); // seconds.
// 	var moveDistance = 200 * delta; // 200 pixels per second
// 	var rotateAngle = Math.PI / 2 * delta;   // pi/2 radians (90 degrees) per second
//     var rotation_matrix = new THREE.Matrix4().identity();
//     const code = e.code;
//     if(e.keyCode == 49){
//         hanleChangeToOverLook();
//     }else if(e.keyCode == 50){
//         //模拟路径行走
//         hanleMockMove();
//     }else if(e.keyCode == 51){
//         //切换第一人称视角
//         hanleChangeToFirstPerson();
//     }
//     if(code == 'KeyW'){
//         arrowPlane.translateY( moveDistance );
//     }else if(code == 'KeyS'){
//         arrowPlane.translateY( -moveDistance );
//     }else if(code == 'KeyQ'){
//         arrowPlane.translateX( -moveDistance );
//     }else if(code == 'KeyE'){
//         arrowPlane.translateX(  moveDistance );	
//     }else if(code == 'KeyA'){
//         arrowPlane.rotateOnAxis( new THREE.Vector3(0,0,1), rotateAngle);
//     }else if(code == 'KeyD'){
//         arrowPlane.rotateOnAxis( new THREE.Vector3(0,0,1), -rotateAngle);
//     }else if(code == 'KeyR'){

//     }else if(code == 'KeyF'){

//     }else if(code == 'KeyZ'){

//     }
//     //hanleChangeToFirstPerson();
}

function handlekeyup(e){
    const code = e.code;
    if (code === 'Digit1') keyStates.Digit1 = false;
    if (code === 'Digit2') keyStates.Digit2 = false;
    if (code === 'Digit3') keyStates.Digit3 = false;
    if (code === 'KeyW') keyStates.W = false;
    if (code === 'KeyA') keyStates.A = false;
    if (code === 'KeyS') keyStates.S = false;
    if (code === 'KeyD') keyStates.D = false;
}

function handleKeyEvent(){
    delta = clock.getDelta();
    var moveDistance = 200 * delta; // 200 pixels per second
	var rotateAngle = Math.PI / 2 * delta;   // pi/2 radians (90 degrees) per second
    var rotation_matrix = new THREE.Matrix4().identity();
    if(keyStates.Digit1){
        hanleChangeToOverLook();
    }else if(keyStates.Digit2){
        //模拟路径行走
        hanleMockMove();
    }else if(keyStates.Digit3){
        //切换第一人称视角
        hanleChangeToFirstPerson();
    }
    if(keyStates.W){
        arrowPlane.translateX( moveDistance );
    }else if(keyStates.S){
        arrowPlane.translateX( -moveDistance );
    }else if(keyStates.A){
        arrowPlane.rotateOnAxis( new THREE.Vector3(0,0,1), rotateAngle);
    }else if(keyStates.D){
        arrowPlane.rotateOnAxis( new THREE.Vector3(0,0,1), -rotateAngle);
    }
}

let lmIndex = 0;

function hanleMockMove(){
    if(!util.isEmpty(pathPoints)){
        isMockMove = true;
        lmIndex = 0;
        stopUpdateRobotLocation();
        //locationMoveRender();
    }
    
}


function locationMoveRender(){
    if (lmIndex < pathPoints.length - 1) {

        const p = pathPoints[lmIndex].clone();
        p.x = p.x - mapWidth/2;
        p.y = p.y + mapHeight/2;
        p.z = p.z + 1000;
        const p1 = pathPoints[lmIndex + 1].clone();
        p1.x = p1.x - mapWidth/2;
        p1.y = p1.y + mapHeight/2;
        p1.z = 11;
        
        trackCamera.position.copy(p);
        trackCamera.lookAt(p1);
        //trackCamera.rotation.set( 0, 0, Math.PI / 3);
        arrowPlane.position.copy(p1);
        arrowPlane.rotation.set(0,0,countAngleByTwoPoint(pathPoints[lmIndex],pathPoints[lmIndex+1])+Math.PI/2);
        lmIndex += 1; //调节速度
        //renderTrackCamera();
        //requestAnimationFrame(locationMoveRender);
    }else{
        lmIndex = 0;
        initArrowLocation();
        isMockMove = false;
        updateRobotLocation();
        //render();
    }
   
}

function renderTrackCamera(){
    trackCamera.far = 10000;
    var relativeCameraOffset = new THREE.Vector3(-200,0,30);
    var cameraOffset = relativeCameraOffset.applyMatrix4( arrowPlane.matrixWorld );
    trackCamera.position.copy(cameraOffset);
    trackCamera.lookAt( arrowPlane.position );
    css2Renderer.render(scene, trackCamera);
    renderer.render(scene, trackCamera);
}

function renderOverLookCamera(){
    css2Renderer.render(scene, camera);
    renderer.render(scene, camera); //执行渲染操作
}

function render(){
    handleKeyEvent();
    //camera.rotation.z = THREE.MathUtils.degToRad(-50);
    if(isMockMove)locationMoveRender();
    if(isVR.value){
        renderTrackCamera();
    }else{
        renderOverLookCamera();
    }
    requestAnimationFrame(render);
}

function hanleChangeToOverLook(){
    isVR.value = false;
}

function hanleChangeToFirstPerson(){
    isVR.value = true;
    //第一人称机位视角
    //console.log(arrowPlane.position,'arrowPlane')
    //renderTrackCamera();
}

function handleVrClick(){
    isVR.value = !isVR.value;
    controls.enabled = !isVR.value;
    console.log(isVR.value,'isVR.value')
    controls.update();
}


//计算夹角
function countAngleByTwoPoint(p1, p2) {
    var p1 = new THREE.Vector3(p1.x, p1.y, p1.z);
    var p2 = new THREE.Vector3(p2.x, p2.y, p2.z);
    //找出中间点位置
    //计算向量长度
    var p12 = p2.clone().sub(p1.clone()); //向量p2减去向量p1
    var distance = p12.length(); //获取距离
    //旋转角度
    var xPoint = new THREE.Vector3(1, 0, 0);
    var angle = Math.acos(p12.clone().dot(xPoint) / distance);
    if (p12.y < 0) angle = -angle;
    return  -(Math.PI / 2 - angle);
}

//角度转弧度
function transAngle(deg){
    return THREE.MathUtils.degToRad(deg);
}


function getWorldPositionByMesh(mesh){
    scene.updateMatrixWorld(true);
    var worldPosition = new THREE.Vector3();
    mesh.getWorldPosition(worldPosition);
    return worldPosition
}

</script>

<style lang="scss" scoped>
.map--mobile-preview{
    width: 100vw;
    height: 100vh;
    overflow: hidden;
    background-color: #1c3042;
    background-image: url(@/assets/images/mapgGrid.png);
    background-repeat: repeat;
    position: relative;
    .canvas-c{
        position: fixed; 
        top: 0; 
        left: 0;
    }
    .float-el{
        pointer-events: none;
        overflow: hidden;
    }
    .mark-box{
        .text-item{
            font-size: 14px;
            text-shadow: 1px -1px 0 #eee, 1px -1px 0 #eee, -1px 1px 0 #eee, 1px 1px 0 #eee;
        }
        .spirit-item{
            width: 24px;
            height: 24px;
            img{
                width: 100%;
                height: 100%;
                object-fit: contain;
            }
        }
    }
    .action-icon{
        position: absolute;
        width: 42px;
        height: 42px;
        border-radius: 50%;
        box-shadow: 0 0 5px rgba(0,0,0,0.5);
        display: flex;
        justify-content: center;
        align-items: center;
        top: 20px;
        right: 20px;
        background-color: rgba(255,255,255,.2);
        color: #fff;
        &.active{
            color: #3291e7;
        }
    }
    .north-icon{
        position: absolute;
        top: 20px;
        left: 20px;
    }
    .target-info{
        width: 200px;
        height: 150px;
        background-color: rgba(255,255,255,.3);
        border-radius: 10px;
        position: fixed;
        right: 20px;
        bottom: 20px;
        color: white;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center
    }
}
</style>

